package cn.buk.tms.dao;

import cn.buk.tms.entity.bill.BillFlightTicket;
import cn.buk.tms.entity.misc.FakeTicketNo;
import cn.buk.tms.entity.order.OrderNoInfo;
import cn.buk.common.util.DateUtil;
import java.util.List;
import jakarta.transaction.Transactional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Repository;

@Repository
@Transactional
public class OrderNoGenerationDaoImpl extends AbstractDao implements OrderNoGenerator {

	private static final Logger logger = LogManager.getLogger(OrderNoGenerationDaoImpl.class);

	/**
	 * 根据订单类型生成订单/账单号
	 * @param enterpriseId
	 * @param orderType
	 * @return
	 */
	@Override
  public String generateOrderNo(final int enterpriseId, final String orderType) {
		String retVal = null;

		String hsql = "select o from OrderNoInfo o where o.enterpriseId = :enterpriseId and o.orderType = :orderType";

		List<OrderNoInfo> infos =
				em.createQuery(hsql, OrderNoInfo.class)
						.setParameter("enterpriseId", enterpriseId)
						.setParameter("orderType", orderType)
						.getResultList();

		OrderNoInfo info = null;
		if (infos.size() == 1) {
      info = infos.get(0);
    }

		if (info == null) {
			info = new OrderNoInfo();
			info.setEnterpriseId(enterpriseId);
			info.setOrderType(orderType);
			info.setOrderNoValue(1);
			em.persist(info);
			em.flush();
		} else {
			int status = em.createQuery("update OrderNoInfo o set o.orderNoValue = o.orderNoValue + 1, o.lastUpdate = :lastUpdate " +
					"where o.id = :id")
					.setParameter("id", info.getId())
					.setParameter("lastUpdate", DateUtil.getCurDateTime())
					.executeUpdate();
			if (status != 1) {
        throw new RuntimeException("To get new order no failed.");
      }
			em.refresh(info);
		}

		retVal = orderType + info.getOrderNoValue();

		return retVal;
	}

	@Override
	public int generateTemplateNo(int enterpriseId, String orderType) {
		String hsql = "select o from OrderNoInfo o where o.enterpriseId = :enterpriseId and o.orderType = :orderType";

		List<OrderNoInfo> infos =
				em.createQuery(hsql, OrderNoInfo.class)
						.setParameter("enterpriseId", enterpriseId)
						.setParameter("orderType", orderType)
						.getResultList();

		OrderNoInfo info = null;
		if (infos.size() == 1) {
			info = infos.get(0);
		}

		if (info == null) {
			info = new OrderNoInfo();
			info.setEnterpriseId(enterpriseId);
			info.setOrderType(orderType);
			info.setOrderNoValue(1);
			em.persist(info);
			em.flush();
		} else {
			int status = em.createQuery("update OrderNoInfo o set o.orderNoValue = o.orderNoValue + 1, o.lastUpdate = :lastUpdate " +
					"where o.id = :id")
					.setParameter("id", info.getId())
					.setParameter("lastUpdate", DateUtil.getCurDateTime())
					.executeUpdate();
			if (status != 1) {
				throw new RuntimeException("To get new order no failed.");
			}
			em.refresh(info);
		}

		return 1000 + info.getOrderNoValue();
	}

	/**
	 * 根据航司，生成虚拟票号
	 * @param enterpriseId
	 * @param twoCode 航司两字代码
	 * @param step
	 * @return 返回模拟的票号或者null
	 */
	@Override
  public String fakeTicketNo(int enterpriseId, String twoCode, final int step) {
		String retVal = null;

		List<FakeTicketNo> infos = em.createQuery("select o from FakeTicketNo o where o.enterpriseId = :enterpriseId and o.twoCode = :twoCode", FakeTicketNo.class)
						.setParameter("enterpriseId", enterpriseId)
						.setParameter("twoCode", twoCode)
						.getResultList();
		if (infos.isEmpty()) {
      return null;
    }

		FakeTicketNo fakeInfo = infos.get(0);
		boolean tryAgain = true;
		int tryCount = 0;
		while(tryAgain) {
			tryAgain = false;

			final int newTicketNo = fakeInfo.getTicketNo() + step + tryCount;

			String newFakeNo = Integer.toString(newTicketNo);
			final String template = "0000000000";
			final String balCode = fakeInfo.getThreeCode();
			final String tickNo = template.substring(0, 10 - newFakeNo.length()) + newFakeNo;

			//查看票号是否已存在于账单中
			List<BillFlightTicket> tickets = em.createQuery("select o from BillFlightTicket o where " +
							"o.enterpriseId = :enterpriseId and o.balanceCode = :balCode and o.ticketNo = :tickNo", BillFlightTicket.class)
							.setParameter("enterpriseId", enterpriseId)
							.setParameter("balCode", balCode)
							.setParameter("tickNo", tickNo)
							.getResultList();
			if (!tickets.isEmpty()) {
				tryAgain = true;
				tryCount++;
				if (tryCount >= 100) {
					return null;
				}
			} else {
				fakeInfo.setTicketNo(newTicketNo);
				fakeInfo.setLastUpdate(DateUtil.getCurDateTime());
				em.merge(fakeInfo);

				retVal = balCode + "-" + tickNo;
			}
		}

		return retVal;
	}

}
